#pragma once

#include "comm/my_defs.h"
#include "comm/my_thread_base.h"
#include "comm/my_log.h"
#include "comm/my_queue.h"
#include "event/my_event.h"
#include "event/my_event_loop.h"

typedef enum {
    MY_AIO_READ         = 1,
    MY_AIO_WRITE        = 2,
    MY_AIO_READ_PING    = 3,
    MY_AIO_WRITE_PING   = 4
} my_aio_opcode_t;

typedef struct {
    my_aio_opcode_t         op;

    int                     fd;
    void                    *buf;
    size_t                  nbytes;
    off_t                   offset;

    // context
    my_dispatch_event_t     dispatch_event;

    int64_t                 setup_time;
    int64_t                 down_time;

    my_syscall_result_t     res;
} my_aio_request_t;

static inline void
my_aio_reqeuest_init(my_aio_request_t *req, my_aio_opcode_t op,
    int fd, void *buf, size_t nbytes, off_t offset,
    my_dispatch_handler_t handler, void *data)
{
    bzero(req, sizeof(my_aio_request_t));

    req->op = op;
    req->fd = fd;
    req->buf = buf;
    req->nbytes = nbytes;
    req->offset = offset;

    req->dispatch_event.handler = handler;

    // swap data and save_data in loop_executer.
    req->dispatch_event.data = data;
    req->dispatch_event.save_data = req;
}


typedef struct {
    my_mutex_t              mutex;
    my_cond_t               cond;
    my_queue_t              extern_queue;
    my_atomic_int64_t       current_task;
    int64_t                 tasks_limit;

    my_atomic_int64_t       stop;
} my_aio_loop_data_t;


static inline void
my_aio_loop_data_init(my_aio_loop_data_t *loop_data, int64_t tasks_limit)
{
    bzero(loop_data, sizeof(my_aio_loop_data_t));
    my_mutex_init(&loop_data->mutex);
    my_cond_init(&loop_data->cond);
    my_queue_init(&loop_data->extern_queue);
    loop_data->tasks_limit = tasks_limit;
}


typedef struct {
    int                     n_read_threads;
    int                     n_write_threads;

    my_aio_loop_data_t      read_loop_data;
    my_aio_loop_data_t      write_loop_data;

    my_thread_base_t        *read_threads;
    my_thread_base_t        *write_threads;
} my_aio_manager_t;

void my_aio_manager_start(my_aio_manager_t *aio_manager,
    int n_read_threads, int n_write_threads,
    int64_t read_task_limit, int64_t write_task_limit);

void my_aio_manager_stop(my_aio_manager_t *aio_manager);

// the following interfaces can only be called in the event loop.
my_bool_t my_aio_post_event(my_aio_manager_t *aio_manager, my_aio_request_t *req);